package com.shopping.mall.core.module.goodsSpecification.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shopping.mall.core.module.attributeKey.mapper.AttributeKeyMapper;
import com.shopping.mall.core.module.attributeValue.mapper.AttributeValueMapper;
import com.shopping.mall.core.module.cart.entity.Cart;
import com.shopping.mall.core.module.cart.mapper.CartMapper;
import com.shopping.mall.core.module.goodData.entity.GoodData;
import com.shopping.mall.core.module.goodData.service.GoodDataService;
import com.shopping.mall.core.module.goods.entity.Goods;
import com.shopping.mall.core.module.goods.mapper.GoodsMapper;
import com.shopping.mall.core.module.goodsSpecification.vo.GoodsSpecificationVo;
import com.shopping.mall.core.module.goodsSpecification.entity.GoodsSpecification;
import com.shopping.mall.core.module.goodsSpecification.entity.NumPrice;
import com.shopping.mall.core.module.goodsSpecification.mapper.GoodsSpecificationMapper;
import com.shopping.mall.core.module.goodsSpecification.mapper.NumPriceMapper;
import com.shopping.mall.core.module.goodsSpecification.service.GoodsSpecificationService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shopping.mall.base.http.ResponseState;
import com.shopping.mall.base.http.Result;
import com.shopping.mall.base.util.WrapperUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Stream;

/**
 * <p>
 * GoodsSpecification服务实现类
 * </p>
 *
 * @author zzy
 * @since 2021-08-28
 */
@Validated
@Service
public class GoodsSpecificationServiceImpl extends ServiceImpl<GoodsSpecificationMapper, GoodsSpecification> implements GoodsSpecificationService {

    @Autowired
    private GoodsSpecificationMapper goodsSpecificationMapper;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private NumPriceMapper numPriceMapper;
    @Autowired
    private AttributeKeyMapper attributeKeyMapper;
    @Autowired
    private AttributeValueMapper attributeValueMapper;
    @Autowired
    private Logger logger;
    @Autowired
    private GoodDataService goodDataService;
    @Autowired
    private CartMapper cartMapper;

    /**
     * 返回替换内容id后的specification json
     *
     * @param id
     * @return
     */
    @Override
    public GoodsSpecification specificationJsonInfo(String id) {
        try {
            final GoodsSpecification goodsSpecification = goodsSpecificationMapper.selectById(id);
            final String specification = goodsSpecification.getSpecification();
            final List<Map> specifications = JSON.parseArray(specification, Map.class);
            specifications.forEach(map -> {
                final Object key = map.get("key");
                final Object value = map.get("value");
                final String attributeKey = attributeKeyMapper.selectById(String.valueOf(key)).getAttributeKey();
                final String attributeValue = attributeValueMapper.selectById(String.valueOf(value)).getAttributeValue();
                map.replaceAll((k, v) -> {
                    if (String.valueOf(k).equals("key")) {
                        return attributeKey;
                    } else if (String.valueOf(k).equals("value")) {
                        return attributeValue;
                    } else return v;
                });
            });
            final String s = JSON.toJSONString(specifications);
            goodsSpecification.setSpecification(s);
            return goodsSpecification;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    /**
     * 添加规格
     *
     * @param goodsSpecificationVo : 规格接收类
     * @return Result<Object>
     */
    @Override
    @Transactional
    public Result<Object> addGoodsSpecification(GoodsSpecificationVo goodsSpecificationVo) {
        final String specification = JSON.toJSONString(goodsSpecificationVo.getSpecification());
        GoodsSpecification goodsSpecification = new GoodsSpecification();
        goodsSpecification.setMaxNumber(goodsSpecificationVo.getMaxNumber());
        goodsSpecification.setGoodsId(goodsSpecificationVo.getGoodsId());
        goodsSpecification.setSpecification(specification);
        goodsSpecification.setType(goodsSpecificationVo.getType());
        goodsSpecification.setStock(goodsSpecificationVo.getStock());
        goodsSpecification.setPrice(goodsSpecificationVo.getPrice());
        //FIXME discountPrice暂时不写,跟price一样
        goodsSpecification.setDiscountPrice(goodsSpecificationVo.getPrice());
        final List<NumPrice> numPriceList = goodsSpecificationVo.getNumPriceList();
        //id为空,新增
        if (goodsSpecificationVo.getId() == null) {
            final int i = goodsSpecificationMapper.insert(goodsSpecification);
            if (i == 0) {
                logger.error("规格添加失败,事务回滚");
                throw new RuntimeException("规格添加失败");
            }
            final String specificationId = goodsSpecification.getId();
            numPriceList.forEach(numPrice -> {
                numPrice.setId(null);
                numPrice.setSpecificationId(specificationId);
                final int i1 = numPriceMapper.insert(numPrice);
                if (i1 == 0) {
                    logger.error("数量-价格添加失败,事务回滚");
                    throw new RuntimeException("数量-价格添加失败");
                }
            });
        } else {//id不为空,更新
            final String specificationId = goodsSpecificationVo.getId();
            goodsSpecification.setId(specificationId);
            final int i = goodsSpecificationMapper.updateById(goodsSpecification);
            if (i == 0) {
                logger.error("规格修改失败,事务回滚");
                throw new RuntimeException("规格修改失败");
            }
            List<String> numPriceNotDeleteIds = new ArrayList<>();
            QueryWrapper<NumPrice> numPriceDeleteWrapper = new QueryWrapper<>();
            QueryWrapper<NumPrice> queryWrapper = new QueryWrapper<>();//判断数据库中是否已存在这个数量的对应的numPrice
            queryWrapper.eq("specification_id", specificationId);
            final Stream<Integer> numberStream = numPriceMapper.selectList(queryWrapper).stream().map(NumPrice::getNumber);
            numPriceList.forEach(numPrice -> {
                numPrice.setSpecificationId(specificationId);
                changePriceWithNumWhenIdExist(numPrice, numPriceNotDeleteIds, numberStream);
            });
            numPriceDeleteWrapper.eq("specification_id", specificationId);
            if (!numPriceNotDeleteIds.isEmpty()) {
                numPriceDeleteWrapper.notIn("id", numPriceNotDeleteIds);
            }
            final int delete = numPriceMapper.delete(numPriceDeleteWrapper);
            logger.info("删除了{}行numPrice", delete);
        }
        goodsUpdate(goodsSpecificationVo.getGoodsId());
        return Result.OK();
    }

    /**
     * 数量改变价格(增改删),当goodsSpecification的id存在时
     *
     * @param numPrice
     * @return
     */
    public void changePriceWithNumWhenIdExist(NumPrice numPrice, List<String> notDeleteIds, Stream<Integer> numberStream) {
        if (numPrice.getId() == null) {
            if (numberStream.anyMatch(num -> Objects.equals(num, numPrice.getNumber()))) {
                logger.warn("数据库中已存在这个数量的对应的numPrice");
                throw new RuntimeException("数据库中已存在这个数量的对应的numPrice");
            }
            final int i = numPriceMapper.insert(numPrice);
            if (i == 0) {
                logger.error("数量-价格添加失败,事务回滚");
                throw new RuntimeException("数量-价格添加失败");
            }
        } else {
            final int i = numPriceMapper.updateById(numPrice);
            if (i == 0) {
                logger.error("数量-价格更新失败,事务回滚");
                throw new RuntimeException("数量-价格更新失败");
            }
        }
        notDeleteIds.add(numPrice.getId());
    }

    /**
     * 根据规格信息返回规格
     *
     * @param specification
     * @return
     */
    @Override
    public Result<Object> specificationInfo(List<Map<String, String>> specification) {
        final List<GoodsSpecification> list = goodsSpecificationMapper.getBySpecification(specification);
        if (!list.isEmpty()) {
            final GoodsSpecification goodsSpecification = list.get(0);
            GoodData goodData = new GoodData();
            goodData.setGoodId(goodsSpecification.getGoodsId());
            goodData.setSpecificationId(goodsSpecification.getId());
            goodDataService.addVisit(goodData);
            final List<NumPrice> numPriceList = numPriceMapper.selectList(new QueryWrapper<NumPrice>().eq("specification_id", goodsSpecification.getId()));
            numPriceList.sort((i1, i2) -> (int) (i1.getRealPrice() - i2.getRealPrice()));
            Map<String, Object> data = new HashMap<>();
            data.put("GoodsSpecification", goodsSpecification);
            data.put("numPriceList", numPriceList);
            return Result.OK(data);
        } else {
            return Result.OK(null);
        }
    }

    /**
     * 分页查询
     *
     * @param current：页码
     * @param size：每页条数
     * @param goodsSpecification：筛选条件
     * @return IPage<GoodsSpecification>
     */
    @Override
    public IPage<GoodsSpecification> getGoodsSpecificationPage(Integer current, Integer size, GoodsSpecification goodsSpecification) {
        QueryWrapper<GoodsSpecification> queryWrapper = WrapperUtils.queryWrapper(goodsSpecification);
        Page<GoodsSpecification> goodsSpecificationPage = new Page<>(current, size);
        return goodsSpecificationMapper.selectPage(goodsSpecificationPage, queryWrapper);
    }

    /**
     * 查询所有
     *
     * @param goodsSpecification：筛选条件
     * @return List<GoodsSpecification>
     */
    @Override
    public List<GoodsSpecification> getAll(GoodsSpecification goodsSpecification) {
        QueryWrapper<GoodsSpecification> queryWrapper = WrapperUtils.queryWrapper(goodsSpecification);
        return goodsSpecificationMapper.selectList(queryWrapper);
    }

    /**
     * 通过id删除
     *
     * @param id：goodsSpecificationId
     * @return Result<Object>
     */
    @Override
    public Result<Object> deleteById(String id) {
        GoodsSpecification goodsSpecification = goodsSpecificationMapper.selectById(id);
        if (goodsSpecification == null) {
            return Result.error(ResponseState.TARGET_NOT_EXIST.getValue(), ResponseState.TARGET_NOT_EXIST.getMessage());
        }
        LambdaQueryWrapper<Cart> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Cart::getSpecificationId,id);
        cartMapper.delete(lambdaQueryWrapper);
        goodsSpecificationMapper.deleteById(id);
        goodsUpdate(goodsSpecification.getGoodsId());
        return Result.OK();
    }

    /**
     * 批量删除
     *
     * @param ids：id列表
     * @return Result<Object>
     */
    @Override
    public Result<Object> batchDelete(List<String> ids) {
        UpdateWrapper<GoodsSpecification> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("id", ids);
        goodsSpecificationMapper.delete(updateWrapper);
        return Result.OK();
    }

    /**
     * 更新商品stock,price,currentPrice
     * FIXME 原价现价暂时一样
     *
     * @param goodsId
     */
    @Override
    public void goodsUpdate(String goodsId) {
        QueryWrapper<GoodsSpecification> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("goods_id", goodsId).select("stock", "price");
        final List<GoodsSpecification> goodsSpecificationList = goodsSpecificationMapper.selectList(queryWrapper);
        final Optional<Integer> reduce = goodsSpecificationList.stream().map(GoodsSpecification::getStock).reduce(Integer::sum);
        final Optional<Double> minPrice = goodsSpecificationList.stream().map(GoodsSpecification::getPrice).min(Comparator.comparingDouble(i -> i));
        Goods goods = new Goods();
        goods.setId(goodsId);
        if (reduce.isPresent()) {
            goods.setStock(reduce.get());
        } else {
            goods.setStock(0);
            logger.error("查询不到库存信息,商品停止出售");
            goods.setStatus(0);
        }
        if (minPrice.isPresent()) {
            logger.info("最低价{}",minPrice.get());
            goods.setPrice(minPrice.get());
            goods.setCurrentPrice(minPrice.get());
        } else {
            goods.setPrice(null);
            goods.setCurrentPrice(null);
            logger.error("查询不到最低价,商品停止出售");
            goods.setStatus(0);
        }
        final int i = goodsMapper.updateById(goods);
        logger.info("商品更新了{}行", i);
    }
}